package com.itydl.sweepview1.view;

import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

/**
 * @author ydl
 * @version 自定义测拉删除控件
 */

public class SweepView extends FrameLayout {

    private ViewDragHelper mDragHelper;
    private View mRightView;//右侧带置顶和删除按钮的View
    private View mLeftView;//左侧内容View
    private int mRightWidth;//右侧View的宽度
    private int mWidth;//控件的宽度==左侧View的宽度
    private int mHeight;//控件的高度==左侧View的高度

    /**
     * 拖拽状态枚举
     */
    public static enum States{
        CLOSE,//关闭
        OPEN,//打开
        DRAGING//拖拽
    }

    private States state = States.CLOSE;//默认是关闭状态
    private OnDragSweepViewListener mSweepViewListener;//拖拽监听器

    public OnDragSweepViewListener getSweepViewListener() {
        return mSweepViewListener;
    }

    /**
     * 设置控件拖拽监听器
     * @param sweepViewListener
     */
    public void setOnSweepViewListener(OnDragSweepViewListener sweepViewListener) {
        mSweepViewListener = sweepViewListener;
    }

    public States getState() {
        return state;
    }

    public void setState(States state) {
        this.state = state;
    }

    /**
     * 拖拽SweepView监听器
     */
    public interface OnDragSweepViewListener{
        /**
         * 打开状态
         * @param sweepView
         *      当前拖拽的View
         */
        void open(SweepView sweepView);

        /**
         * 关闭状态
         * @param sweepView
         *      当前拖拽的View
         */
        void close(SweepView sweepView);

        /**
         * 开始进入打开状态
         * @param sweepView
         *      当前拖拽的View
         */
        void onStartOpen(SweepView sweepView);

        /**
         * 开始进入关闭状态
         * @param sweepView
         *      当前拖拽的View
         */
        void onStartClose(SweepView sweepView);
    }

    public SweepView(Context context) {
        this(context,null);
    }

    public SweepView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDragHelper = ViewDragHelper.create(this,1.0f,new MyCallBack());
    }

    class MyCallBack extends ViewDragHelper.Callback{

        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return true;
        }

        //获取视图水平方向拖拽范围，childe被拖拽的view，必须>0，用于动画执行时长的计算。
        @Override
        public int getViewHorizontalDragRange(View child) {
            return mRightWidth;
        }

        // 当touch移动后的回调,返回值决定了将要移动到的水平方向的位置
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            // left建议移动到的位置
            // 当前位置和建议移动到的位置的偏差。
            // 处理边界
            if(child == mRightView){
                if(left < (mWidth-mRightWidth)){
                    left = mWidth-mRightWidth;
                }else if(left > mWidth){
                    left = mWidth;
                }
            }else if(child == mLeftView){
                if(left < -mRightWidth){
                    left = -mRightWidth;
                }else if(left > 0){
                    left = 0;
                }
            }
            return left;
        }

        /**
         * ---------  处理移动，转交移动。处理便随动画，更新状态，执行监听  ---------
         **/
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            // left：当前移动到的水平位置
            // dx：刚刚发生的水平变化量
            if(changedView == mLeftView){
                //移动View
                mRightView.offsetLeftAndRight(dx);
            }else if(changedView == mRightView){
                mLeftView.offsetLeftAndRight(dx);
            }

            handleTouchEvent();

            /*一定重写invalidate方法，并重写computeScroll方法*/
            invalidate();
        }

        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            // up时（手指释放）时候的回调
            // @releasedChild:松开了哪个view
            // @xvel,yvel:速率。xvel>0: 往右滑动的速率  xvel<0:往左滑动的速率。xvel = 0：速度为0
            if(xvel == 0 && mLeftView.getLeft() > -mRightWidth/2){
                close();
            }else if(xvel > 0){
                close();
            }else{
                open();
            }
        }
    }

    /**
     * 处理touch事件，更新控件状态
     */
    private void handleTouchEvent() {
        States lastState = state;
        state = upDataState();
        if(lastState != state && mSweepViewListener!=null){//状态一致的时候不执行，防止多次调用对应的回调方法
            if(state == States.CLOSE){
                mSweepViewListener.close(this);
            }else if(state == States.OPEN){
                mSweepViewListener.open(this);
            }else if(state == States.DRAGING){
                if(lastState == States.CLOSE){
                    //再拖拽就是即将进入打开状态
                    mSweepViewListener.onStartOpen(this);
                }else if(lastState == States.OPEN){
                    //再拖拽就是即将进入关闭
                    mSweepViewListener.onStartClose(this);
                }
            }
        }
    }

    /**
     * 更新当前状态。根据left的值-mRightWidth-->打开；0-->关闭
     * @return
     */
    private States upDataState() {
        int currentLeft = mLeftView.getLeft();
        if(currentLeft == -mRightWidth){
            //打开状态
            return States.OPEN;
        }else if(currentLeft == 0){
            //关闭状态
            return States.CLOSE;
        }
        return States.DRAGING;
    }

    /**
     * 打开右侧内容
     */
    public void open() {
        open(true);
    }

    /**
     * 打开是否需要平滑,默认是true
     * @param shouldSmooth
     */
    public void open(boolean shouldSmooth){
        if(shouldSmooth){
            if(mDragHelper.smoothSlideViewTo(mLeftView,-mRightWidth,0)){
                ViewCompat.postInvalidateOnAnimation(this);
            }
        }else{
            layoutChild(true);
        }
    }

    /**
     * 关闭右侧内容
     */
    public void close() {
        close(true);
    }

    /**
     * 关闭是否需要平滑,默认是true
     * @param shouldSmooth
     */
    public void close(boolean shouldSmooth){
        if(shouldSmooth){
            if(mDragHelper.smoothSlideViewTo(mLeftView,0,0)){
                ViewCompat.postInvalidateOnAnimation(this);
            }
        }else{
            layoutChild(false);
        }
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if(mDragHelper.continueSettling(true)){
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mDragHelper.processTouchEvent(event);
        return true;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //拿到孩子控件
        mRightView = getChildAt(0);
        mLeftView = getChildAt(1);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = this.getMeasuredWidth();
        mHeight = this.getMeasuredHeight();

        mRightWidth = mRightView.getMeasuredWidth();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        //摆放孩子的位置

        layoutChild(false);

    }

    /**
     * 摆放孩子的位置
     * @param isOpen
     *      是否是打开状态
     */
    private void layoutChild(boolean isOpen) {
            //摆放右侧孩子的位置
            Rect rightRect = getRightRect(isOpen);
            mRightView.layout(rightRect.left,rightRect.top,rightRect.right,rightRect.bottom);

            //摆放左侧孩子的位置
            Rect leftRect = getLeftRect(isOpen);
            mLeftView.layout(leftRect.left,leftRect.top,leftRect.right,leftRect.bottom);
    }

    /**
     * 获取左侧布局位置封装对象
     * @return
     */
    private Rect getLeftRect(boolean isOpen) {
        int left = 0;
        if(isOpen){
            left = -mRightWidth;
        }
        return new Rect(left,0,left+mWidth,0+mHeight);
    }

    /**
     * 封装的思想，获取右侧控件位置的封装对象
     * @return
     */
    private Rect getRightRect(boolean isOpen) {
        int left = mWidth;
        if(isOpen){
            left = mWidth-mRightWidth;
        }
        return new Rect(left,0,left+mRightWidth,mHeight);
    }
}
